'''
 ******************************************************************************
 *  Copyright 2010 Vijay Pandurangan.
 *  Parts copyright Jumo International.
 *
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 ******************************************************************************

@author: vijayp
'''
import ExpDH

def GetDescendants(ins, basecls):
  #@memoize 
  def get_all_bases(cls):
    bases = []
    for b in cls.__bases__:
      bases.append(b)
      bases += get_all_bases(b)
    return bases
  rval = []
  for entity_name in dir(ins):
    thing = getattr(ins, entity_name)
    if inspect.isclass(thing):
      allbases = get_all_bases(thing)
      if basecls in allbases:
        rval.append(thing)
  return rval    

class Ting3HTTPServer(object):
  ''' This is a simple class you should inherit from. It listens on a port, and 
  implements some basic montitoring handlers. By default, you get rudimentary 
  /varz /statusz, and /quitquitquit handlers. It uses a tornado server, and 
  it's possible to start this in a thread (though it might be a bit buggy).
  
  Exported Data are automatically set up and handled by default. Any classes 
  derived from tornado.web.RequestHandler are recognized and bound automatically 
  as well.  
  
  To use:
  
  class MyHTTPServer(Ting3HTTPServer):
    NAME='My Server Name'
  
    class StopHandler(tornado.web.RequestHandler):
      URL='/stop'
      def get(self):
        StopSomething();
        self.write("Stopped")
    class RootZHandler(tornado.web.RequestHandler):
      URL='/'
      def get(self):
        self.write('my own homepage')
   ...
   ...
   
   
  Then:
  
  http = ManagerHTTPServer(port=self._port_exp)
  http.StartInIOLoop(IOLoop.instance(), startthread=False)
        
  '''

  NAME = 'Default Ting3 server'
  class VarZHandler(tornado.web.RequestHandler):
    URL = r'/varz'
    def get(self):
      logging.error('STARTING')
      self.set_header('Content-Type', 'text/plain')
      self.write(ExpDH.instance().AsText())

  class StatusZHandler(tornado.web.RequestHandler):
    URL = r'/statusz'
    def get(self):
      self.set_header('content-type', 'text/html')
      self.write(ExpDH.instance().AsHTML())

  class QuitHandler(tornado.web.RequestHandler):
    URL = r'/quitquitquit'
    def get(self):
      self.set_header('content-type', 'text/html')
      logging.error('Got Quit from user. dying')
      self.write("Dying in 5 seconds")
      iol = tornado.ioloop.IOLoop.instance()
      #iol.add_timeout(time.time() + 5, iol.stop)
      iol.add_timeout(functools.partial(sys.exit, 0), iol.stop)
  
  class RootHandler(StatusZHandler):
    URL = r'/'
  
  def __init__(self, port, name=None):
    self._name = name
    ExpDH.instance().setTitle(self.NAME if name is None else name)
    ExpDH.instance().AutoAddClass(self)
    assert port
    self._port_exp = port
    self._application = tornado.web.Application()
    self.AttachDefaultHandlers()
    
    
  def AttachDefaultHandlers(self):
    handler_list = [(h.URL, h) for h in 
                    GetDescendants(self, tornado.web.RequestHandler)]
    logging.info('got handler list %s', str(handler_list))
    self._application.add_handlers('.*$', handler_list)
    
  def StartInIOLoop(self, ioloop=None, startthread=False):
    self._ioloop = IOLoop.instance() if ioloop is None else ioloop
    self._server = httpserver.HTTPServer(self._application)
    self._server.listen(self._port_exp)
    logging.info('%s listening on %s', self._name, self._port_exp)
    if startthread:
      #TODO: figure out how to handle excepetions in this thread
      logging.info('starting new listening thread')
      self._thread = thread.start_new_thread(self._ioloop.start, tuple([]))
     

